package org.fujene.memman.backup;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import org.fujene.constants.Constants;
import org.fujene.structure.ContentInfo;
import org.fujene.structure.LookupPointer;
import org.fujene.toolbox.ByteConverter;

public class SnapShotStructure{
	// Dictionary, Invert index, Contents, Appendices: hold current pointer
	private LookupPointer[] firstPoints;
	private LookupPointer[] contentFirstPoints;
	private LookupPointer[] contentSkipPtrFirstPoints;
	private LookupPointer[] appendixFirstPoints;
	private LookupPointer[] lastPoints;
	private LookupPointer[] contentLastPoints;
	private LookupPointer[] contentSkipPtrLastPoints;
	private LookupPointer[] appendixLastPoints;
	private int[] clusterInfos;
	private int[] assignedIDs;
	private long ID;
	private boolean isToFile;
	private String storeDirectory;
	private boolean isCopyToNode;

	private SnapShotStructure(){}

	public SnapShotStructure(int clusterAmount, ContentInfo contentInfo){
		this.firstPoints = new LookupPointer[clusterAmount * Constants.MEMORY_TYPE_KINDS];
		this.contentFirstPoints = new LookupPointer[clusterAmount * contentInfo.contentsNum()];
		this.contentSkipPtrFirstPoints = new LookupPointer[clusterAmount * contentInfo.contentsNum()];
		this.appendixFirstPoints = new LookupPointer[clusterAmount * contentInfo.appendixNum()];
		this.lastPoints = new LookupPointer[clusterAmount * Constants.MEMORY_TYPE_KINDS];
		this.contentLastPoints = new LookupPointer[clusterAmount * contentInfo.contentsNum()];
		this.contentSkipPtrLastPoints = new LookupPointer[clusterAmount * contentInfo.contentsNum()];
		this.appendixLastPoints = new LookupPointer[clusterAmount * contentInfo.appendixNum()];
		this.isToFile = false;
	}

	public SnapShotStructure(String dir){
		this.isToFile = true;
		this.storeDirectory = dir;
	}

	public static SnapShotStructure snapshotAll(LookupPointer[] first, LookupPointer[] contentFirst,
		LookupPointer[] contentSkipFirst, LookupPointer[] appendixFirst, LookupPointer[] last,
		LookupPointer[] contentLast, LookupPointer[] contentSkipLast, LookupPointer[] appendixLast,
		int[] clusters, int[] assignedIDs){
		SnapShotStructure structure = new SnapShotStructure();

		structure.firstPoints = Arrays.copyOf(first, first.length);
		structure.contentFirstPoints = Arrays.copyOf(contentFirst, contentFirst.length);
		structure.contentSkipPtrFirstPoints = Arrays.copyOf(contentSkipFirst, contentSkipFirst.length);
		structure.appendixFirstPoints = Arrays.copyOf(appendixFirst, appendixFirst.length);
		structure.lastPoints = Arrays.copyOf(first, first.length);
		structure.contentLastPoints = Arrays.copyOf(contentLast, contentLast.length);
		structure.contentSkipPtrLastPoints = Arrays.copyOf(contentSkipLast, contentSkipLast.length);
		structure.appendixLastPoints = Arrays.copyOf(appendixLast, appendixLast.length);
		structure.clusterInfos = Arrays.copyOf(clusters, clusters.length);
		structure.isToFile = false;
		structure.assignedIDs = assignedIDs;
		structure.ID = System.currentTimeMillis();

		return structure;
	}
	
	public static SnapShotStructure fromFile(String directory) {
		SnapShotStructure structure = new SnapShotStructure();
		directory += ".backupdata";
		
		File dataFile = new File(directory);
		if(!dataFile.exists()) {
			System.err.println("ERROR: Backup information file didn't open. Stop.");
			return null;
		}
		FileInputStream stream = null;
		try{
			stream = new FileInputStream(dataFile);
			int arrayLen;
			byte[] tmpdata = new byte[8];
			stream.read(tmpdata);
			structure.ID = ByteConverter.byteToLong(tmpdata);
			
			tmpdata = new byte[2];
			stream.read(tmpdata);
			arrayLen = ByteConverter.byteToInt(tmpdata);
			structure.firstPoints = new LookupPointer[arrayLen];
			structure.lastPoints = new LookupPointer[arrayLen];
			
			stream.read(tmpdata);
			arrayLen = ByteConverter.byteToInt(tmpdata);
			structure.contentFirstPoints = new LookupPointer[arrayLen];
			structure.contentLastPoints = new LookupPointer[arrayLen];
			structure.contentSkipPtrFirstPoints = new LookupPointer[arrayLen];
			structure.contentSkipPtrLastPoints = new LookupPointer[arrayLen];

			stream.read(tmpdata);
			arrayLen = ByteConverter.byteToInt(tmpdata);
			structure.appendixFirstPoints = new LookupPointer[arrayLen];
			structure.appendixLastPoints = new LookupPointer[arrayLen];
			
			tmpdata = new byte[LookupPointer.PTR];
			for(int i = 0; i < structure.firstPoints.length; i++) {
				stream.read(tmpdata);
				structure.firstPoints[i] = LookupPointer.fromBytes(tmpdata);
			}
			for(int i = 0; i < structure.lastPoints.length; i++){
				stream.read(tmpdata);
				structure.lastPoints[i] = LookupPointer.fromBytes(tmpdata);
			}
			for(int i = 0; i < structure.contentFirstPoints.length; i++){
				stream.read(tmpdata);
				structure.contentFirstPoints[i] = LookupPointer.fromBytes(tmpdata);
			}
			for(int i = 0; i < structure.contentLastPoints.length; i++){
				stream.read(tmpdata);
				structure.contentLastPoints[i] = LookupPointer.fromBytes(tmpdata);
			}
			for(int i = 0; i < structure.contentSkipPtrFirstPoints.length; i++){
				stream.read(tmpdata);
				structure.contentSkipPtrFirstPoints[i] = LookupPointer.fromBytes(tmpdata);
			}
			for(int i = 0; i < structure.contentSkipPtrLastPoints.length; i++){
				stream.read(tmpdata);
				structure.contentSkipPtrLastPoints[i] = LookupPointer.fromBytes(tmpdata);
			}
			for(int i = 0; i < structure.appendixFirstPoints.length; i++){
				stream.read(tmpdata);
				structure.appendixFirstPoints[i] = LookupPointer.fromBytes(tmpdata);
			}
			for(int i = 0; i < structure.appendixLastPoints.length; i++){
				stream.read(tmpdata);
				structure.appendixLastPoints[i] = LookupPointer.fromBytes(tmpdata);
			}
		}catch(IOException e){
		}finally{
			if(stream != null) try{
				stream.close();
			}catch(IOException e){
			}
		}
		
		return structure;
	}

	public void toFile(String directory){
		directory += ".backupdata";

		File dataFile = new File(directory);
		try{
			dataFile.createNewFile();
		}catch(IOException e){
			System.err.println("ERROR: Backup information file didn't create.");
		}

		FileOutputStream stream = null;
		try{
			stream = new FileOutputStream(dataFile);
			stream.write(ByteConverter.longToByte(ID, 8));
			stream.write(ByteConverter.intToByte(firstPoints.length, 2));
			stream.write(ByteConverter.intToByte(contentFirstPoints.length, 2));
			stream.write(ByteConverter.intToByte(appendixFirstPoints.length, 2));
			for(int i = 0; i < firstPoints.length; i++)
				stream.write(firstPoints[i].toBytes());
			for(int i = 0; i < lastPoints.length; i++)
				stream.write(lastPoints[i].toBytes());
			for(int i = 0; i < contentFirstPoints.length; i++)
				stream.write(contentFirstPoints[i].toBytes());
			for(int i = 0; i < contentLastPoints.length; i++)
				stream.write(contentLastPoints[i].toBytes());
			for(int i = 0; i < contentSkipPtrFirstPoints.length; i++)
				stream.write(contentSkipPtrFirstPoints[i].toBytes());
			for(int i = 0; i < contentSkipPtrLastPoints.length; i++)
				stream.write(contentSkipPtrLastPoints[i].toBytes());
			for(int i = 0; i < appendixFirstPoints.length; i++)
				stream.write(appendixFirstPoints[i].toBytes());
			for(int i = 0; i < appendixLastPoints.length; i++)
				stream.write(appendixLastPoints[i].toBytes());
		}catch(IOException e){
			e.printStackTrace();
		}finally{
			if(stream != null) try{
				stream.close();
			}catch(IOException e){}
		}
	}

	public LookupPointer firstPoint(int index){
		return firstPoints[index];
	}

	public LookupPointer lastPoint(int index){
		return lastPoints[index];
	}

	public LookupPointer contentFirstPoint(int index){
		return contentFirstPoints[index];
	}

	public LookupPointer contentLastPoint(int index){
		return contentLastPoints[index];
	}

	public LookupPointer contentSkipPtrFirstPoint(int index){
		return contentSkipPtrFirstPoints[index];
	}

	public LookupPointer contentSkipPtrLastPoint(int index){
		return contentSkipPtrLastPoints[index];
	}

	public LookupPointer appendixFirstPoint(int index){
		return appendixFirstPoints[index];
	}

	public LookupPointer appendixLastPoint(int index){
		return appendixLastPoints[index];
	}

	public LookupPointer[] firstPoints(){
		return firstPoints;
	}

	public LookupPointer[] lastPoints(){
		return lastPoints;
	}

	public LookupPointer[] contentFirstPoints(){
		return contentFirstPoints;
	}

	public LookupPointer[] contentLastPoints(){
		return contentLastPoints;
	}

	public LookupPointer[] contentSkipPtrFirstPoints(){
		return contentSkipPtrFirstPoints;
	}

	public LookupPointer[] contentSkipPtrLastPoints(){
		return contentSkipPtrLastPoints;
	}

	public LookupPointer[] appendixFirstPoints(){
		return appendixFirstPoints;
	}

	public LookupPointer[] appendixLastPoints(){
		return appendixLastPoints;
	}

	public int getClusterInfos(int index){
		return clusterInfos[index];
	}

	public int[] assignedID(){
		return assignedIDs;
	}

	public void setBackupToDisk(String targetDir){
		isToFile = true;
		storeDirectory = targetDir;
		toFile(targetDir);
	}

	public void copyToNode(){
		this.isCopyToNode = true;
	}

	public boolean isToFile(){
		return isToFile;
	}

	public boolean isCopyToNode(){
		return isCopyToNode;
	}

	public String storeDirectory(){
		return storeDirectory;
	}

	public long ID(){
		return ID;
	}
}
